package com.aube.plugin.gallery.preview;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Bitmap;
import android.os.CountDownTimer;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.Scroller;

import com.aube.plugin.gallery.PictureImp;
import com.aube.plugin.gallery.R;
import com.huyn.baseframework.model.Picture;
import com.huyn.baseframework.utils.StringUtils;
import com.huyn.baseframework.utils.SysUtil;
import com.huyn.baseframework.utils.Utils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Created by huyaonan on 16/6/17.
 */
public class GalleryListView extends ViewGroup implements GestureDetector.OnGestureListener {

    private float mLastMotionY;// 最后点击的点
    private GestureDetector detector;
    public int move = 0;// 移动距离
    int MAXMOVE = 20000;// 最大允许的移动距离
    private Scroller mScroller;
    int up_excess_move = 0;// 往上多移的距离
    int down_excess_move = 0;// 往下多移的距离
    private final static int TOUCH_STATE_REST = 0;
    private final static int TOUCH_STATE_SCROLLING = 1;
    private int mTouchSlop;
    private int mTouchState = TOUCH_STATE_REST;
    protected int firstLoadToIndex = 0;
    private Context mContext;
    private List<PictureImp> mPictures = new ArrayList<>();

    private static final int ITEM_MARGIN = 2;

    private Bitmap mBgBitmap;

    private ConcurrentHashMap<Integer, Boolean> mPicLoadedChildren = new ConcurrentHashMap<>();

    public GalleryListView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context);
    }

    public GalleryListView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public GalleryListView(Context context) {
        this(context, null);
    }

    private void init(Context context) {
        mContext = context;
        mScroller = new Scroller(context);
        detector = new GestureDetector(this);

        final ViewConfiguration configuration = ViewConfiguration.get(context);
        mTouchSlop = configuration.getScaledTouchSlop();
    }

    public void setItemBg(Bitmap bitmap) {
        mBgBitmap = bitmap;
    }

    @Override
    protected void onLayout(boolean arg0, int arg1, int arg2, int arg3, int arg4) {
        int count = getChildCount();
        int width = arg3 - arg1;
        int x = 0;
        int y = ITEM_MARGIN;
        for (int i = 0; i < count; i++) {
            View viewchild = getChildAt(i);
            LayoutParams para = viewchild.getLayoutParams();
            int childwidth = para.width;
            int childheight = para.height;
            viewchild.layout(x, y, x + childwidth, y + childheight);
            if (i > 0 && y < SysUtil.getScreenHeight(mContext)) {
                firstLoadToIndex = i;
            }
            x += childwidth + ITEM_MARGIN;
            if (x > width - 10) {
                x = 0;
                y += childheight + ITEM_MARGIN;
            }
        }
        MAXMOVE = y - arg4 + arg2;
    }

    private int getPictureSize() {
        return mPictures == null ? 0 : mPictures.size();
    }

    private GalleryItem.OnImageGetter mImageCache;
    private List<ImageView> mImageArray;
    private HashMap<String, Size> mSizeMaps;

    public static class Size {
        public int width;
        public int height;
        public Size(int w, int h) {
            width = w;
            height = h;
        }
    }

    private void addToSizeMap(String url, int width, int height) {
        if(mSizeMaps == null)
            mSizeMaps = new HashMap<>();
        mSizeMaps.put(url, new Size(width, height));
    }

    int size = 0;
    public void addChildView(List<PictureImp> pictures, int firstViewHeight, boolean firstLoad) {
        int childWidth = 0;
        int childHeight = 0;
        int childWidthSec = 0;
        int childHeightSec = 0;
        int toLoadIndex = 0;
        int visibleHeight = SysUtil.getAbsoluteScreenHeight(mContext) - firstViewHeight;
        int tempHeight = 0;
        int counter = 1;

        if(mImageCache == null)
            mImageCache = new GalleryItem.OnImageGetter() {
                @Override
                public ImageView getImgView() {
                    if(mImageArray != null && mImageArray.size() > 0) {
                        return mImageArray.remove(0);
                    } else {
                        size++;
                        Utils.sysout("init size.........................." + size);
                        return new ImageView(mContext);
                    }
                }

                @Override
                public Size getSize(String url) {
                    return mSizeMaps.get(url);
                }

                @Override
                public void markImgAdded(int index) {
                    synchronized (mPicLoadedChildren) {
                        mPicLoadedChildren.put(index, true);
                    }
                }
            };

        int pictureSize = getPictureSize();
        if(mPictures == null || mPictures.size() == 0)
            mPictures = pictures;
        else
            mPictures.addAll(pictures);

        boolean autoLoad = firstLoad;

        for (int i = 0; i < pictures.size(); i++) {
            int width = SysUtil.getScreenWidth(mContext);
            final Picture picture = pictures.get(i);
            if (!StringUtils.isNotBlank(picture.getPictureUrl())) {
                continue;
            }

            float rate = ((float) picture.getWidth()) / picture.getHeight();
            if (rate > 2.0f || i == pictures.size() - 1) {
                childWidth = width;
                childHeight = (int) (childWidth / rate);
                GalleryItem movieItem = new GalleryItem(mContext);
                int index = addChildView(movieItem, childWidth, childHeight, picture.getPictureUrl());
                addOnClikListener(movieItem, i + pictureSize);

                addToSizeMap(picture.getPictureUrl(), childWidth, childHeight);

                if(autoLoad)
                    movieItem.attachImg(index, picture.getPictureUrl(), mImageCache);
                movieItem.setBackground(mBgBitmap);

                counter++;
            } else {
                Picture picture2 = pictures.get(i + 1);
                childWidthSec = (int) ((((float) picture.getHeight()) / picture2.getHeight()) * picture2.getWidth());
                float rateAll = ((float) (picture.getWidth() + childWidthSec)) / width;
                childWidth = (int) (picture.getWidth() / rateAll);
                childWidthSec = (int) (childWidthSec / rateAll) + 1;
                childHeightSec = childHeight = (int) (childWidth / rate);
                float ratenew = ((float) width) / childHeight;
                if (ratenew > 2.0f || i == pictures.size() - 2) {
                    GalleryItem movieItem = new GalleryItem(mContext);
                    int index1 = addChildView(movieItem, childWidth, childHeight, picture.getPictureUrl());
                    GalleryItem movieItem2 = new GalleryItem(mContext);
                    int index2 = addChildView(movieItem2, childWidthSec, childHeightSec, picture2.getPictureUrl());
                    addOnClikListener(movieItem, i + pictureSize);
                    addOnClikListener(movieItem2, i + 1 + pictureSize);
                    i++;

                    addToSizeMap(picture.getPictureUrl(), childWidth, childHeight);
                    addToSizeMap(picture2.getPictureUrl(), childWidthSec, childHeightSec);

                    if(autoLoad) {
                        movieItem.attachImg(index1, picture.getPictureUrl(), mImageCache);
                        movieItem2.attachImg(index2, picture2.getPictureUrl(), mImageCache);
                    }
                    movieItem.setBackground(mBgBitmap);
                    movieItem2.setBackground(mBgBitmap);

                    counter+=2;
                } else {
                    Picture picture3 = pictures.get(i + 2);
                    int childWidthThr = 0;
                    int childHeightThr = 0;
                    childWidthThr = (int) ((((float) childHeight) / picture3.getHeight()) * picture3.getWidth());
                    float ratethr = ((float) (width + childWidthThr)) / width;
                    childWidth = (int) (childWidth / ratethr);
                    childWidthSec = (int) (childWidthSec / ratethr);
                    childWidthThr = (int) (childWidthThr / ratethr) + 1;
                    childHeightThr = childHeightSec = childHeight = (int) (childWidth / rate);

                    GalleryItem movieItem = new GalleryItem(mContext);
                    int index1 = addChildView(movieItem, childWidth, childHeight, picture.getPictureUrl());
                    GalleryItem movieItem2 = new GalleryItem(mContext);
                    int index2 = addChildView(movieItem2, childWidthSec, childHeightSec, picture2.getPictureUrl());
                    GalleryItem movieItem3 = new GalleryItem(mContext);
                    int index3 = addChildView(movieItem3, childWidthThr, childHeightThr, picture3.getPictureUrl());
                    addOnClikListener(movieItem, i + pictureSize);
                    addOnClikListener(movieItem2, i + 1 + pictureSize);
                    addOnClikListener(movieItem3, i + 2 + pictureSize);
                    i += 2;

                    addToSizeMap(picture.getPictureUrl(), childWidth, childHeight);
                    addToSizeMap(picture2.getPictureUrl(), childWidthSec, childHeightSec);
                    addToSizeMap(picture3.getPictureUrl(), childWidthThr, childHeightThr);

                    if(autoLoad) {
                        movieItem.attachImg(index1, picture.getPictureUrl(), mImageCache);
                        movieItem2.attachImg(index2, picture2.getPictureUrl(), mImageCache);
                        movieItem3.attachImg(index3, picture3.getPictureUrl(), mImageCache);
                    }
                    movieItem.setBackground(mBgBitmap);
                    movieItem2.setBackground(mBgBitmap);
                    movieItem3.setBackground(mBgBitmap);

                    counter+=3;
                }
            }

            if(firstLoad) {
                tempHeight += childHeight;

                if (tempHeight <= visibleHeight + childHeight)
                    toLoadIndex = counter;
                else
                    autoLoad = false;
            }
        }

        if(firstLoad) {
            if (toLoadIndex > 0)
                firstLoadToIndex = toLoadIndex;
        }
    }

    private void addOnClikListener(final GalleryItem view, final int index) {
        view.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                if (itemClickListener != null) {
                    itemClickListener.OnItemClickListener(view, mPictures, index);
                }
            }
        });
    }

    private int addChildView(GalleryItem view, int width, int height, String url) {
        view.setTag(R.id.posterview_tag_url, url);
        addView(view, new LayoutParams(width, height));
        return getChildCount()-1;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        for(int i=0; i < getChildCount(); i++) {
            LayoutParams params = getChildAt(i).getLayoutParams();
            getChildAt(i).measure(MeasureSpec.makeMeasureSpec(params.width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(params.height, MeasureSpec.EXACTLY));
        }

        int measureWidth = measureSize(widthMeasureSpec);
        int measureHeight = measureSize(heightMeasureSpec);

        setMeasuredDimension(measureWidth, measureHeight);
    }

    private int measureSize(int measureSpec) {
        int result = 0;
        int mode = MeasureSpec.getMode(measureSpec);// 得到模式
        int size = MeasureSpec.getSize(measureSpec);// 得到尺寸

        switch (mode) {
            case MeasureSpec.AT_MOST:
            case MeasureSpec.EXACTLY:
                result = size;
                break;
        }
        return result;
    }

    @Override
    public boolean onDown(MotionEvent arg0) {
        return true;
    }

    @Override
    public boolean onFling(MotionEvent arg0, MotionEvent arg1, float arg2, float arg3) {
        // 随手指 快速拨动的代码
        if (up_excess_move == 0 && down_excess_move == 0) {
            int slow = -(int) arg3;
            mScroller.fling(0, move, 0, slow, 0, 0, 0, MAXMOVE);
            move = mScroller.getFinalY();
            computeScroll();
            new CountDownTimer(mScroller.getDuration(), mScroller.getDuration()) {
                @Override
                public void onTick(long arg0) {
                }

                @Override
                public void onFinish() {
                    updateView();

                    loadMore();
                }
            }.start();
        }
        return false;
    }

    @Override
    public void onLongPress(MotionEvent arg0) {
    }

    @Override
    public boolean onScroll(MotionEvent arg0, MotionEvent arg1, float arg2, float arg3) {
        return false;
    }

    int startIndex = -1;
    int endIndex = -1;
    protected void updateView() {
        try {
            startIndex = -1;
            for (int i = 1; i < getChildCount(); i++) {
                View viewchild = getChildAt(i);
                int location[] = { 0, 0 };
                viewchild.getLocationOnScreen(location);
                if (location[1] < SysUtil.getScreenHeight(mContext)) {
                    if(location[1] + viewchild.getHeight() >= 0) {
                        if (startIndex < 0)
                            startIndex = i;

                        String url = (String) viewchild.getTag(R.id.posterview_tag_url);
                        if(viewchild instanceof GalleryItem) {
                            ((GalleryItem) viewchild).attachImg(i, url, mImageCache);
                        }

                        endIndex = i;
                    }
                } else {
                    return;
                }
            }
        } catch (Exception e) {
        }
    }

    @Override
    public void onShowPress(MotionEvent arg0) {
    }

    @Override
    public boolean onSingleTapUp(MotionEvent arg0) {
        return false;
    }

    @Override
    public void computeScroll() {
        if(mScroller.isFinished()) {
            recycleView();
            return;
        }
        if (mScroller.computeScrollOffset()) {
            // 返回当前滚动Y方向的偏移
            int y = mScroller.getCurrY();
            scrollTo(0, y);
//            postInvalidate();

            invalidate();
            if(mScrollListener != null)
                mScrollListener.onScrolled(y);
        }
    }

    private void recycleView() {
        if(endIndex <= startIndex)
            return;
        synchronized (mPicLoadedChildren) {
            Iterator<Integer> keyIterator = mPicLoadedChildren.keySet().iterator();
            while (keyIterator.hasNext()) {
                int index = keyIterator.next();
                Utils.Log("GALLERY", "start recycle..." + index + "===" + startIndex + "/" + endIndex);
                if(index < startIndex || index > endIndex) {
                    GalleryItem item = (GalleryItem) getChildAt(index);
                    ImageView view = item.detachImg();
                    if(mImageArray == null)
                        mImageArray = new ArrayList<>();
                    if(view != null)
                        mImageArray.add(view);

                    keyIterator.remove();
                    Utils.Log("GALLERY", "recycle..." + index);
                }
            }
        }
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        final float y = ev.getY();
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mLastMotionY = y;
                mTouchState = mScroller.isFinished() ? TOUCH_STATE_REST : TOUCH_STATE_SCROLLING;
                break;
            case MotionEvent.ACTION_MOVE:
                final int yDiff = (int) Math.abs(y - mLastMotionY);
                boolean yMoved = yDiff > mTouchSlop;
                // 判断是否是移动
                if (yMoved) {
                    mTouchState = TOUCH_STATE_SCROLLING;
                }
                break;
            case MotionEvent.ACTION_UP:
                mTouchState = TOUCH_STATE_REST;
                break;
        }
        return mTouchState != TOUCH_STATE_REST;
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        final float y = ev.getY();
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                if (!mScroller.isFinished()) {
                    mScroller.forceFinished(true);
                    recycleView();
                    move = mScroller.getCurrY();
                }
                mLastMotionY = y;
                break;
            case MotionEvent.ACTION_MOVE:
                if (ev.getPointerCount() == 1) {
                    // 随手指 拖动的代码
                    int deltaY = 0;
                    deltaY = (int) (mLastMotionY - y);
                    mLastMotionY = y;
//                    System.out.println(MAXMOVE + "_____" + deltaY);
                    if (deltaY < 0) {
                        // 判断上移 是否滑过头
//                        System.out.println("_____+" + up_excess_move + "|" +move);
                        if (up_excess_move == 0) {
                            if (move > 0) {
                                int move_this = Math.max(-move, deltaY);
                                move = move + move_this;
                                scrollBy(0, move_this);
                            } else if (move == 0) {// 如果已经是最顶端 继续往下拉
//                                down_excess_move = down_excess_move - deltaY / 2;// 记录下多往下拉的值
//                                scrollBy(0, deltaY / 2);
                            }
                        } else if (up_excess_move > 0)// 之前有上移过头
                        {
                            if (up_excess_move >= (-deltaY)) {
                                up_excess_move = up_excess_move + deltaY;
                                scrollBy(0, deltaY);
                            } else {
                                up_excess_move = 0;
                                scrollBy(0, -up_excess_move);
                            }
                        }
                    } else if (deltaY > 0) {
                        // 上移
//                        System.out.println("=====+" + down_excess_move + "|" +move);
                        if (down_excess_move == 0) {
                            if (MAXMOVE - move > 0) {
                                int move_this = Math.min(MAXMOVE - move, deltaY);
                                move = move + move_this;
                                scrollBy(0, move_this);
                            } else if (MAXMOVE - move == 0) {
                                if (up_excess_move <= 100) {
                                    //up_excess_move = up_excess_move + deltaY / 2;
                                    //scrollBy(0, deltaY / 2);
                                }
                            }
                        } else if (down_excess_move > 0) {
                            if (down_excess_move >= deltaY) {
                                //down_excess_move = down_excess_move - deltaY;
                                //scrollBy(0, deltaY);
                            } else {
                                //down_excess_move = 0;
                                //scrollBy(0, down_excess_move);
                            }
                        }
                    }

                    if(mScrollListener != null)
                        mScrollListener.onScrolled(getScrollY());
                }
                break;
            case MotionEvent.ACTION_UP:
                // 多滚是负数 记录到move里
                if (up_excess_move > 0) {
                    // 多滚了 要弹回去
                    //scrollBy(0, -up_excess_move);
                    animPullView(up_excess_move);
                    invalidate();
                    //up_excess_move = 0;
                }
                if (down_excess_move > 0) {
                    // 多滚了 要弹回去
                    //scrollBy(0, down_excess_move);
                    animPullView(-down_excess_move);
                    invalidate();
                    //down_excess_move = 0;

                }
                mTouchState = TOUCH_STATE_REST;

                loadMore();
                break;
        }
        return this.detector.onTouchEvent(ev);
    }

    private void loadMore() {
        if(Math.abs(MAXMOVE - move) <= 200 && mScrollListener != null)
            mScrollListener.onScrollToEnd();
    }

    private void animPullView(int distance) {
        ValueAnimator animator = ValueAnimator.ofFloat(distance, 0);
        animator.setDuration(300);
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float pos = (float) animation.getAnimatedValue();
                scrollTo(0, (int) pos);

                if(mScrollListener != null)
                    mScrollListener.onScrolled((int) pos);
            }
        });
        animator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                down_excess_move = 0;
                up_excess_move = 0;
            }
        });
        animator.start();
    }

    public interface OnChildClickListener {
        public void OnItemClickListener(GalleryItem view, List<PictureImp> pictures, int position);
    }

    public void setOnItemClickListener(OnChildClickListener itemClickListener) {
        this.itemClickListener = itemClickListener;
    }

    private OnChildClickListener itemClickListener;

    public void onDestroy() {
        removeAllViews();
        if(mImageArray != null)
            mImageArray.clear();
        if(mPicLoadedChildren != null)
            mPicLoadedChildren.clear();
        if(mPictures != null)
            mPictures.clear();
        if(mSizeMaps != null)
            mSizeMaps.clear();
        if(mBgBitmap != null)
            mBgBitmap = null;
    }

    public interface OnScrollListener {
        public void onScrolled(int y);
        public void onScrollToEnd();
    }

    private OnScrollListener mScrollListener;
    public void setOnScrollListener(OnScrollListener listener) {
        this.mScrollListener = listener;
    }

}

